{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ad4393ba-240a-45d9-87af-9798e2a2fec9",
   "metadata": {},
   "source": [
    "# Tensor类实现\n",
    "这里对Tensor中的自动微分机制进行了简单实现，文章链接 [09 深度神经网络框架的基础：自动微分](https://zhuanlan.zhihu.com/p/27693066757)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "259b73ed-ebfe-4da8-963a-7833e0a9ec90",
   "metadata": {},
   "source": [
    "## 基础属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "0a85c0ec-8716-4e39-9352-38c4f63272cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Tensor(object):\n",
    "    def __init__(self, data,creators=None, creation_op=None):\n",
    "        self.data = data\n",
    "        self.grad = None\n",
    "        self.creation_op = creation_op \n",
    "        self.creators = creators \n",
    "        \n",
    "    def __add__(self, other):\n",
    "        return Tensor(self.data+other.data,\n",
    "                     creators=[self,other],\n",
    "                     creation_op=\"add\")\n",
    "        \n",
    "    def __mul__(self, other):\n",
    "        return Tensor(self.data*other.data,\n",
    "                     creators=[self,other],\n",
    "                     creation_op=\"mul\")\n",
    "        \n",
    "    def __str__(self):\n",
    "        return str(self.data.__str__())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "7c938b2f-532e-4f83-90f0-68a808b883c4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "40\n",
      "4\n",
      "10\n",
      "mul\n"
     ]
    }
   ],
   "source": [
    "a = Tensor(2)\n",
    "b = a * Tensor(3)    \n",
    "c = a + Tensor(2)\n",
    "d = b + Tensor(4)\n",
    "e = c * d\n",
    "\n",
    "print(e)\n",
    "print(e.creators[0])\n",
    "print(e.creators[1])\n",
    "print(e.creation_op)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3aae2a74-6a43-44c3-bc93-062d14234d14",
   "metadata": {},
   "source": [
    "## 添加反向传播机制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "0bf6ccce-c92a-4ea3-9133-53df01b48602",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Tensor(object):\n",
    "    def __init__(self, data,creators=None, creation_op=None):\n",
    "        self.data = data\n",
    "        self.grad = None\n",
    "        self.creation_op = creation_op \n",
    "        self.creators = creators \n",
    "\n",
    "    def backward(self, grad=-1): \n",
    "        if(grad==-1):\n",
    "            self.grad = 1\n",
    "        else:\n",
    "            if (self.grad is None):\n",
    "                self.grad = grad\n",
    "            else:\n",
    "                self.grad+=grad\n",
    "        \n",
    "        if(self.creation_op == \"add\"): \n",
    "            self.creators[0].backward(self.grad) \n",
    "            self.creators[1].backward(self.grad)  \n",
    "        \n",
    "        if(self.creation_op == \"mul\"): \n",
    "            self.creators[0].backward(self.grad*self.creators[1].data) \n",
    "            self.creators[1].backward(self.grad*self.creators[0].data)\n",
    "        \n",
    "    def __add__(self, other):\n",
    "        return Tensor(self.data+other.data,\n",
    "                     creators=[self,other],\n",
    "                     creation_op=\"add\")\n",
    "        \n",
    "    def __mul__(self, other):\n",
    "        return Tensor(self.data*other.data,\n",
    "                     creators=[self,other],\n",
    "                     creation_op=\"mul\")\n",
    "        \n",
    "    def __str__(self):\n",
    "        return str(self.data.__str__())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "775e0c32-b711-4588-8c07-01bdf0a325c7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "22\n"
     ]
    }
   ],
   "source": [
    "a = Tensor(2)\n",
    "b = a * Tensor(3)    \n",
    "c = a + Tensor(2)\n",
    "d = b + Tensor(4)\n",
    "e = c * d\n",
    "\n",
    "e.backward()\n",
    "\n",
    "print(a.grad)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "639a9c8a-4376-40b4-9e19-50418eb8933a",
   "metadata": {},
   "source": [
    "## 数组功能支持，其他运算符号支持"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "d9e7c761-a07d-4ca4-93c2-4da7b28913a1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "class Tensor(object):\n",
    "    def __init__(self, data,creators=None, creation_op=None):\n",
    "        self.data = np.array(data)\n",
    "        self.grad = None\n",
    "        self.creation_op = creation_op \n",
    "        self.creators = creators \n",
    "\n",
    "    def backward(self, grad=None): \n",
    "        if(grad is None):\n",
    "            self.grad = Tensor(np.ones_like(self.data))\n",
    "        else:\n",
    "            if (self.grad is None):\n",
    "                self.grad = grad\n",
    "            else:\n",
    "                self.grad+=grad\n",
    "        \n",
    "        if(self.creation_op == \"add\"): \n",
    "            self.creators[0].backward(self.grad) \n",
    "            self.creators[1].backward(self.grad)  \n",
    "        \n",
    "        if(self.creation_op == \"sub\"):\n",
    "            self.creators[0].backward(Tensor(self.grad.data), self)\n",
    "            self.creators[1].backward(Tensor(self.grad.__neg__().data), self)\n",
    "\n",
    "        if(self.creation_op == \"mul\"): \n",
    "            self.creators[0].backward(self.grad*self.creators[1]) \n",
    "            self.creators[1].backward(self.grad*self.creators[0])                  \n",
    "                    \n",
    "        if(self.creation_op == \"mm\"):\n",
    "            c0 = self.creators[0]\n",
    "            c1 = self.creators[1]\n",
    "            new = self.grad.mm(c1.transpose())\n",
    "            c0.backward(new)\n",
    "            new = self.grad.transpose().mm(c0).transpose()\n",
    "            c1.backward(new)\n",
    "        \n",
    "    def __add__(self, other):\n",
    "        return Tensor(self.data+other.data,\n",
    "                     creators=[self,other],\n",
    "                     creation_op=\"add\")\n",
    "        \n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        return Tensor(self.data - other.data,\n",
    "                      creators=[self,other],\n",
    "                      creation_op=\"sub\")\n",
    "        \n",
    "    def __mul__(self, other):\n",
    "        return Tensor(self.data*other.data,\n",
    "                     creators=[self,other],\n",
    "                     creation_op=\"mul\")\n",
    "\n",
    "    def mm(self, x):\n",
    "        return Tensor(self.data.dot(x.data),\n",
    "                      creators=[self,x],\n",
    "                      creation_op=\"mm\")\n",
    "        \n",
    "    def __str__(self):\n",
    "        return str(self.data.__str__())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "7a877f88-7748-4770-ba49-e5831335512d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 2  4  9]\n",
      " [ 4  6 12]\n",
      " [ 6  8 15]]\n",
      "[[1 2 3]\n",
      " [2 3 4]\n",
      " [3 4 5]]\n",
      "[2 2 3]\n"
     ]
    }
   ],
   "source": [
    "a = Tensor([2, 2, 3])\n",
    "b = Tensor([2, 3, 4]) \n",
    "c = Tensor([[1,2,3],[2,3,4],[3,4,5]])\n",
    "\n",
    "d = a * c\n",
    "print(d)\n",
    "\n",
    "d.backward(Tensor(np.array([1,1,1])))\n",
    "print(a.grad.data)\n",
    "print(c.grad.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0936b8b9-f628-400a-bc68-6c16a79d6d12",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "myenv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
